package com.liao.badminton.exception;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.liao.badminton.code.ProjectException;
import com.liao.badminton.code.RespCodeMessage;
import com.liao.badminton.code.ResponseRest;
import com.liao.badminton.code.util.ResponseUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLNonTransientException;
import java.util.List;
import java.util.stream.Collectors;

import static com.liao.badminton.code.RespCodeMessage.SECURITY_ACCOUNT_UN_AUTHOR;

@ControllerAdvice
@Log4j2
public class MyExceptionController {
    @ExceptionHandler(RuntimeException.class)
    public void error(Exception e, HttpServletResponse response, HttpServletRequest request)  throws AccessDeniedException {
        String servletPath = request.getServletPath();
        ResponseRest result = ResponseRest.fail(servletPath);
        e.printStackTrace();
        log.error("MyExceptionController -------系统异常：{}", e);
        if (e instanceof AccessDeniedException) {
//            return;
            throw (AccessDeniedException)e;
            //ProjectException.newException(SECURITY_ACCOUNT_UN_AUTHOR, "无权限访问该项目");//被MyAuthorException 拦截
        }
        if (e instanceof ProjectException) {
            result.setCode(((ProjectException) e).getCode());
            result.setMsg(e.getMessage());
        }
        if (e instanceof NonTransientDataAccessException) {
            result.setCode(RespCodeMessage.MYSQL_DATA_ERROR.getCode());
            result.setMsg("数据库操作异常，请联系管理员");
        }


        ResponseUtils.out(response, result);
    }

    /**
     * 参数校验异常处理
     * @param e
     * @param response
     * @param request
     * @throws AccessDeniedException
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public void paramError(MethodArgumentNotValidException e, HttpServletResponse response, HttpServletRequest request)  throws AccessDeniedException {
        String servletPath = request.getServletPath();
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        List<String> errorsMessages = allErrors.stream()
                .map(error -> error.getDefaultMessage())
                .collect(Collectors.toList());
        ResponseRest result = ResponseRest.fail(servletPath, RespCodeMessage.PARAM_ERROR,errorsMessages.toString());
        ResponseUtils.out(response, result);
    }

    /**
     * 参数格式异常处理
     * @param e
     * @param
     * @return
     */
    @ExceptionHandler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public void handle(HttpMessageNotReadableException e, HttpServletResponse response,HttpServletRequest request) {
        ResponseRest result = null;
        Throwable rootCause = e.getRootCause();
        String servletPath = request.getServletPath();
        // 无效格式异常处理。比如：目标格式为数值，输入为非数字的字符串（"80.5%"、"8.5.1"、"张三"）。
        if (rootCause instanceof InvalidFormatException) {
            String format = "HttpMessageNotReadableException-InvalidFormatException（Http消息不可读异常-无效格式异常）：%s";
            String errorMessage = String.format(format, e.getMessage());
            result = ResponseRest.fail(servletPath, RespCodeMessage.PARAM_FORMAT_ERROR, errorMessage);
            ResponseUtils.out(response, result);
        }

        String errorMessage = String.format("HttpMessageNotReadableException（Http消息不可读异常）：%s", e.getMessage());
        result =  ResponseRest.fail(servletPath, RespCodeMessage.PARAM_FORMAT_ERROR, errorMessage);
        ResponseUtils.out(response, result);
    }

}
